namespace BassettData.Robots
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// Moves a robot in the given direction.
    /// </summary>
    /// <remarks>Breaking this into its own class ensure that 
    /// the movement is not the responsibility either of the direction
    /// or of the location.</remarks>
    internal static class Mover
    {
        /// <summary>
        /// A static list of the behaviour associated with each Direction.
        /// </summary>
        private static Dictionary<Direction, MoveInstructions> moveInstructions = new Dictionary<Direction, MoveInstructions>
            {
                {
                    Direction.East, 
                    new MoveInstructions
                    {
                        AvenueIncrement = 1, StreetIncrement = 0, DirectionToLeft = Direction.North
                    }
                },
                {
                    Direction.North,
                    new MoveInstructions
                    {
                        AvenueIncrement = 0, StreetIncrement = 1, DirectionToLeft = Direction.West
                    }
                },
                {
                    Direction.West,
                    new MoveInstructions
                    {
                        AvenueIncrement = -1, StreetIncrement = 0, DirectionToLeft = Direction.South
                    }
                },
                {
                    Direction.South, 
                    new MoveInstructions
                    {
                        AvenueIncrement = 0, StreetIncrement = -1, DirectionToLeft = Direction.East
                    }
                }
            };

        /// <summary>
        /// Gets the direction to the left of the given direction.
        /// </summary>
        /// <param name="currentDirection">The current direction.</param>
        /// <returns>The direction to the left.</returns>
        public static Direction GetDirectionToLeft(Direction currentDirection)
        {
            return moveInstructions[currentDirection].DirectionToLeft;
        }

        /// <summary>
        /// Gets the location that is found if we move in the given direction by one unit.
        /// Does not validate this new location against the World.
        /// </summary>
        /// <param name="currentDirection">The current direction.</param>
        /// <param name="location">The location.</param>
        /// <returns>The new location.</returns>
        public static Location Move(Direction currentDirection, Location location)
        {
            var moveInstruction = moveInstructions[currentDirection];
            return new Location(
                location.Avenue + moveInstruction.AvenueIncrement,
                location.Street + moveInstruction.StreetIncrement);
        }

        /// <summary>
        /// Instructions for a particular direction on how to move.
        /// </summary>
        private class MoveInstructions
        {
            /// <summary>
            /// Gets or sets the avenue increment.
            /// </summary>
            /// <value>The avenue increment.</value>
            public int AvenueIncrement { get; set; }

            /// <summary>
            /// Gets or sets the street increment.
            /// </summary>
            /// <value>The street increment.</value>
            public int StreetIncrement { get; set; }

            /// <summary>
            /// Gets or sets the direction to the left.
            /// </summary>
            /// <value>The direction to the left.</value>
            public Direction DirectionToLeft { get; set; }
        }
    }
}
